1 using System;
2 using
System.Collections.Generic;
3 using
System.Linq;
4 using
System.Text;
5 using
System.Xml;
6 using
System.Xml.Linq;
7
8 using
UnityEditor;
9 using
UnityEngine;
10
11 namespace
Tiled2Unity
12 {
13     
// Handles a Mesh being imported.
14     
// At this point we should have everything we need to build out any prefabs for the tiled map object
15     
partial class ImportTiled2Unity
16     {
17         
public void MeshImported(string objPath)
18         {
19             
string xmlPath = ImportUtils.GetXmlPath(objPath);
20             XDocument doc = XDocument.Load(xmlPath);
21             
foreach (var xmlPrefab in doc.Root.Elements("Prefab"))
22             {
23                 CreatePrefab(xmlPrefab, objPath);
24             }
25         }
26
27         
private void CreatePrefab(XElement xmlPrefab, string objPath)
28         {
29             
var customImporters = GetCustomImporterInstances();
30
31             
// Part 1: Create the prefab
32             
string prefabName = xmlPrefab.Attribute("name").Value;
33             
float prefabScale = ImportUtils.GetAttributeAsFloat(xmlPrefab, "scale", 1.0f);
34             GameObject tempPrefab =
new GameObject(prefabName);
35             HandleCustomProperties(tempPrefab, xmlPrefab, customImporters);
36
37             
// Part 2: Build out the prefab
38             AddGameObjectsTo(tempPrefab, xmlPrefab, objPath, customImporters);
39
40             
// Part 3: Allow for customization from other editor scripts to be made on the prefab
41             
// (These are generally for game-specific needs)
42             CustomizePrefab(tempPrefab, customImporters);
43
44             
// Part 3.5: Apply the scale only after all children have been added
45             tempPrefab.transform.localScale =
new Vector3(prefabScale, prefabScale, prefabScale);
46
47             
// Part 4: Save the prefab, keeping references intact.
48             
string prefabPath = ImportUtils.GetPrefabPath(prefabName);
49             UnityEngine.Object finalPrefab = AssetDatabase.LoadAssetAtPath(prefabPath,
typeof(GameObject));
50
51             
if (finalPrefab == null)
52             {
53                 
// The prefab needs to be created
54                 ImportUtils.ReadyToWrite(prefabPath);
55                 finalPrefab = PrefabUtility.CreateEmptyPrefab(prefabPath);
56             }
57
58             
// Replace the prefab, keeping connections based on name.
59             PrefabUtility.ReplacePrefab(tempPrefab, finalPrefab, ReplacePrefabOptions.ReplaceNameBased);
60
61             
// Destroy the instance from the current scene hiearchy.
62             UnityEngine.Object.DestroyImmediate(tempPrefab);
63         }
64
65         
private void AddGameObjectsTo(GameObject parent, XElement xml, string objPath, IList<ICustomTiledImporter> customImporters)
66         {
67             
foreach (XElement goXml in xml.Elements("GameObject"))
68             {
69                 
string name = ImportUtils.GetAttributeAsString(goXml, "name", "");
70                 
string copyFrom = ImportUtils.GetAttributeAsString(goXml, "copy", "");
71
72                 GameObject child =
null;
73                 
if (!String.IsNullOrEmpty(copyFrom))
74                 {
75                     child = CreateCopyFromMeshObj(copyFrom, objPath);
76                     
if (child == null)
77                     {
78                         
// We're in trouble. Errors should already be in the log.
79                         
return;
80                     }
81                 }
82                 
else
83                 {
84                     child =
new GameObject();
85                 }
86
87                 
if (!String.IsNullOrEmpty(name))
88                 {
89                     child.name = name;
90                 }
91
92                 
float x = ImportUtils.GetAttributeAsFloat(goXml, "x", 0);
93                 
float y = ImportUtils.GetAttributeAsFloat(goXml, "y", 0);
94                 child.transform.position =
new Vector3(x, y, 0);
95
96                 
// Assign the child to the parent
97                 child.transform.parent = parent.transform;
98
99                 
// Do we have any collision data
100                 AddCollidersTo(child, goXml);
101
102                 
// Do we have any children of our own?
103                 AddGameObjectsTo(child, goXml, objPath, customImporters);
104
105                 
// Does this game object have a tag?
106                 AssignTagTo(child, goXml);
107
108                 
// Does this game object have a layer?
109                 AssignLayerTo(child, goXml);
110
111                 
// Are there any custom properties?
112                 HandleCustomProperties(child, goXml, customImporters);
113             }
114         }
115
116         
private void AssignLayerTo(GameObject gameObject, XElement xml)
117         {
118             
string layerName = ImportUtils.GetAttributeAsString(xml, "layer", "");
119             
if (String.IsNullOrEmpty(layerName))
120                 
return;
121
122             
int layerId = LayerMask.NameToLayer(layerName);
123             
if (layerId == -1)
124             {
125                 
string msg = String.Format("Layer '{0}' is not defined for '{1}'. Check project settings in Edit->Project Settings->Tags & Layers",
126                     layerName,
127                     GetFullGameObjectName(gameObject.transform));
128                 Debug.LogError(msg);
129                 
return;
130             }
131
132             
// Set the layer on ourselves (and our children)
133             AssignLayerIdTo(gameObject, layerId);
134         }
135
136         
private void AssignLayerIdTo(GameObject gameObject, int layerId)
137         {
138             
if (gameObject == null)
139                 
return;
140
141             gameObject.layer = layerId;
142
143             
foreach (Transform child in gameObject.transform)
144             {
145                 
if (child.gameObject == null)
146                     
continue;
147
148                 
// Do not set the layerId on a child that has already had his layerId explicitly set
149                 
if (child.gameObject.layer != 0)
150                     
continue;
151
152                 AssignLayerIdTo(child.gameObject, layerId);
153             }
154         }
155
156         
private void AssignTagTo(GameObject gameObject, XElement xml)
157         {
158             
string tag = ImportUtils.GetAttributeAsString(xml, "tag", "");
159             
if (String.IsNullOrEmpty(tag))
160                 
return;
161
162             
// Let the user know if the tag doesn't exist in our project sttings
163             
try
164             {
165                 gameObject.tag = tag;
166             }
167             
catch (UnityException)
168             {
169                 
string msg = String.Format("Tag '{0}' is not defined for '{1}'. Check project settings in Edit->Project Settings->Tags & Layers",
170                     tag,
171                     GetFullGameObjectName(gameObject.transform));
172                 Debug.LogError(msg);
173             }
174         }
175
176         
private string GetFullGameObjectName(Transform xform)
177         {
178             
if (xform == null)
179                 
return "";
180             
string parentName = GetFullGameObjectName(xform.parent);
181
182             
if (String.IsNullOrEmpty(parentName))
183                 
return xform.name;
184
185             
return String.Format("{0}/{1}", parentName, xform.name);
186         }
187
188         
private void AddCollidersTo(GameObject gameObject, XElement xml)
189         {
190             
// Box colliders
191             
foreach (XElement xmlBoxCollider2D in xml.Elements("BoxCollider2D"))
192             {
193                 BoxCollider2D collider = gameObject.AddComponent<BoxCollider2D>();
194                 
float width = ImportUtils.GetAttributeAsFloat(xmlBoxCollider2D, "width");
195                 
float height = ImportUtils.GetAttributeAsFloat(xmlBoxCollider2D, "height");
196                 collider.size =
new Vector2(width, height);
197                 collider.offset =
new Vector2(width * 0.5f, -height * 0.5f);
198             }
199
200             
// Circle colliders
201             
foreach (XElement xmlCircleCollider2D in xml.Elements("CircleCollider2D"))
202             {
203                 CircleCollider2D collider = gameObject.AddComponent<CircleCollider2D>();
204                 
float radius = ImportUtils.GetAttributeAsFloat(xmlCircleCollider2D, "radius");
205                 collider.radius = radius;
206                 collider.offset =
new Vector2(radius, -radius);
207             }
208
209             
// Edge colliders
210             
foreach (XElement xmlEdgeCollider2D in xml.Elements("EdgeCollider2D"))
211             {
212                 EdgeCollider2D collider = gameObject.AddComponent<EdgeCollider2D>();
213                 
string data = xmlEdgeCollider2D.Element("Points").Value;
214
215                 
// The data looks like this:
216                 
// x0,y0 x1,y1 x2,y2 ...
217                 
var points = from pt in data.Split(' ')
218                              
let x = Convert.ToSingle(pt.Split(',')[0])
219                              
let y = Convert.ToSingle(pt.Split(',')[1])
220                              
select new Vector2(x, y);
221
222                 collider.points = points.ToArray();
223
224             }
225
226             
// Polygon colliders
227             
foreach (XElement xmlPolygonCollider2D in xml.Elements("PolygonCollider2D"))
228             {
229                 PolygonCollider2D collider = gameObject.AddComponent<PolygonCollider2D>();
230
231                 
var paths = xmlPolygonCollider2D.Elements("Path").ToArray();
232                 collider.pathCount = paths.Count();
233
234                 
for (int p = 0; p < collider.pathCount; ++p)
235                 {
236                     
string data = paths[p].Value;
237
238                     
// The data looks like this:
239                     
// x0,y0 x1,y1 x2,y2 ...
240                     
var points = from pt in data.Split(' ')
241                                  
let x = Convert.ToSingle(pt.Split(',')[0])
242                                  
let y = Convert.ToSingle(pt.Split(',')[1])
243                                  
select new Vector2(x, y);
244
245                     collider.SetPath(p, points.ToArray());
246                 }
247             }
248         }
249
250         
private GameObject CreateCopyFromMeshObj(string copyFromName, string objPath)
251         {
252             
// Find a matching game object within the mesh object and "copy" it
253             
// (In Unity terms, the Instantiated object is a copy)
254             UnityEngine.Object[] objects = AssetDatabase.LoadAllAssetsAtPath(objPath);
255             
foreach (var obj in objects)
256             {
257                 
if (obj.name != copyFromName)
258                     
continue;
259
260                 
// We have a match but is it a game object?
261                 GameObject gameObj = GameObject.Instantiate(obj)
as GameObject;
262                 
if (gameObj == null)
263                     
continue;
264
265                 
// Reset the name so it is not decorated by the Instantiate call
266                 gameObj.name = obj.name;
267                 
return gameObj;
268             }
269
270             
// If we're here then there's an error with the mesh name
271             Debug.LogError(String.Format(
"No mesh named '{0}' to copy from.", copyFromName));
272             
return null;
273         }
274
275         
private void HandleCustomProperties(GameObject gameObject, XElement goXml, IList<ICustomTiledImporter> importers)
276         {
277             
var props = from p in goXml.Elements("Property")
278                         
select new { Name = p.Attribute("name").Value, Value = p.Attribute("value").Value };
279
280             
if (props.Count() > 0)
281             {
282                 
var dictionary = props.OrderBy(p => p.Name).ToDictionary(p => p.Name, p => p.Value);
283                 
foreach (ICustomTiledImporter importer in importers)
284                 {
285                     importer.HandleCustomProperties(gameObject, dictionary);
286                 }
287             }
288         }
289
290         
private void CustomizePrefab(GameObject prefab, IList<ICustomTiledImporter> importers)
291         {
292             
foreach (ICustomTiledImporter importer in importers)
293             {
294                 importer.CustomizePrefab(prefab);
295             }
296         }
297
298         
private IList<ICustomTiledImporter> GetCustomImporterInstances()
299         {
300             
// Report an error for ICustomTiledImporter classes that don't have the CustomTiledImporterAttribute
301             
var errorTypes = from a in AppDomain.CurrentDomain.GetAssemblies()
302                              
from t in a.GetTypes()
303                              
where typeof(ICustomTiledImporter).IsAssignableFrom(t)
304                              
where !t.IsAbstract
305                              
where Attribute.GetCustomAttribute(t, typeof(CustomTiledImporterAttribute)) == null
306                              
select t;
307             
foreach (var t in errorTypes)
308             {
309                 Debug.LogError(String.Format(
"ICustomTiledImporter type '{0}' is missing CustomTiledImporterAttribute", t));
310             }
311
312             
// Find all the types with the CustomTiledImporterAttribute, instantiate them, and give them a chance to customize our prefab
313             
var types = from a in AppDomain.CurrentDomain.GetAssemblies()
314                         
from t in a.GetTypes()
315                         
where typeof(ICustomTiledImporter).IsAssignableFrom(t)
316                         
where !t.IsAbstract
317                         
from attr in Attribute.GetCustomAttributes(t, typeof(CustomTiledImporterAttribute))
318                         
let custom = attr as CustomTiledImporterAttribute
319                         
orderby custom.Order
320                         
select t;
321
322             
var instances = types.Select(t => (ICustomTiledImporter)Activator.CreateInstance(t));
323             
return instances.ToList();
324         }
325
326     }
// end class
327 }
// end namespace


Handles a Mesh being imported.

At this point we should have everything we need to build out any prefabs for the tiled map object

Part 1: Create the prefab

Part 2: Build out the prefab

Part 3: Allow for customization from other editor scripts to be made on the prefab

(These are generally for game-specific needs)

Part 3.5: Apply the scale only after all children have been added

Part 4: Save the prefab, keeping references intact.

The prefab needs to be created

Replace the prefab, keeping connections based on name.

Destroy the instance from the current scene hiearchy.

We're in trouble. Errors should already be in the log.

Assign the child to the parent

Do we have any collision data

Do we have any children of our own?

Does this game object have a tag?

Does this game object have a layer?

Are there any custom properties?

Set the layer on ourselves (and our children)

Do not set the layerId on a child that has already had his layerId explicitly set

Let the user know if the tag doesn't exist in our project sttings

Box colliders

Circle colliders

Edge colliders

The data looks like this:

x0,y0 x1,y1 x2,y2 ...

Polygon colliders

The data looks like this:

x0,y0 x1,y1 x2,y2 ...

Find a matching game object within the mesh object and "copy" it

(In Unity terms, the Instantiated object is a copy)

We have a match but is it a game object?

Reset the name so it is not decorated by the Instantiate call

If we're here then there's an error with the mesh name

Report an error for ICustomTiledImporter classes that don't have the CustomTiledImporterAttribute

Find all the types with the CustomTiledImporterAttribute, instantiate them, and give them a chance to customize our prefab

} end class

} end namespace




Trò chơi đua xe động vật trong UNITY Engine 114.731 lượt xem

Gõ tìm kiếm nhanh...